/**
 *
 */
package com.cmcc.pcap.packet.tcp;

import java.util.Arrays;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.cmcc.pcap.packet.util.PacketAnalysisConfig;

/**
 * @Date 2018年3月21日 上午11:01:51
 * @author Amish
 * 用于判断应用层协议类型，并根据配置决定是否返回对应的协议类型，供调用类决定是否继续处理等
 * 在分段情况下，一般只有第一个数据包能判断应用层协议类型
 */
public class TcpProtocolFilter {

	public static Logger logger = LogManager.getLogger(TcpProtocolFilter.class);
	
	//HTTP 定义HTTP协议所有30种方法字段名 + “http”字段
	public static String HTTP_type[] = {"CONNECT","HEAD","PUT","DELETE","POST","GET","TRACE","OPTION","PROPFIND","PROPPATCH",
		"MKCOL","COPY","MOVE","LOCK","UNLOCK","PATCH","BPROPFIND","BPROPPATCH","BCOPY","BDELETE",
		"BMOVE","NOTIFY","POLL","SEARCH","SUBSCRIBE","UNSUBSCRIBE","ORDERPATCH","ACL","UPDATE","MERGE"};
	
	
	//DELETE
	//UPDATE
	
	//FTP
	
	//TODO 配置从哪读，怎么读？

	
	/**
	 * 如果是需要处理的应用层协议，直接返回协议名称，如TcpProtocol.HTTP
	 * 如果是需要过滤掉的应用层协议，返回TcpProtocol.NOTDEAL
	 * 如没有应用层数据的包，返回null
	 * 如果是无法判断的应用层协议（包括分段后续包），返回null
	 * @param tcpPacketDecorator
	 * @return
	 */
	public static TcpProtocol filterTcpProtocol(TcpPacketDecorator tcpPacketDecorator){
		
		if(tcpPacketDecorator.tcpPacket.getPayload() == null){//该判断多余0613add
			return null;
		}
		
		//TODO 扫描应用层数据判断协议类型
		//TODO 如何判断HTTP？？？？？HTTP\GET\POST?
		
		
		//parseProtocol(tcpPacketDecorator.tcpPacket.data);  //TODO
		
		//TODO 根据配置决定放回值
		
		String dst_port =  Integer.toString(tcpPacketDecorator.tcpPacket.getHeader().getDstPort().valueAsInt());
		String src_port =  Integer.toString(tcpPacketDecorator.tcpPacket.getHeader().getSrcPort().valueAsInt());
	
		if((dst_port.equals("443") || src_port.equals("443")) && Arrays.asList(PacketAnalysisConfig.getConfigAsString("tcp.protocol.filter").split(",")).contains("https")){
			logger.debug("https filtered");
			return TcpProtocol.HTTPS;
		}
		if(parseProtocol(tcpPacketDecorator.tcpPacket.getPayload().getRawData()) == TcpProtocol.HTTP && Arrays.asList(PacketAnalysisConfig.getConfigAsString("tcp.protocol.filter").split(",")).contains("http")){//TODO 如果判断结果符合配置，返回对应协议，这里暂时默认返回HTTP
		//if((dst_port.equals("8080") || src_port.equals("8080") || dst_port.equals("80") || src_port.equals("80")) && Arrays.asList(PacketAnalysisConfig.getConfigAsString("tcp.protocol.filter").split(",")).contains("http")){//TODO 如果判断结果符合配置，返回对应协议，这里暂时默认返回HTTP
		//if(parseProtocol(tcpPacketDecorator.getData()) == TcpProtocol.HTTP){//TODO 如果判断结果符合配置，返回对应协议，这里暂时默认返回HTTP
			return TcpProtocol.HTTP;//TcpProtocol.HTTP;
		}


		logger.debug("tcp filtered");
		return TcpProtocol.TCP;

		
/*
		if(!((dst_port.equals("443") || src_port.equals("443")) && Arrays.asList(PacketAnalysisConfig.getConfigAsString("tcp.protocol.filter").split(",")).contains("https"))
			&& !(parseProtocol(tcpPacketDecorator.getData(1)) == TcpProtocol.HTTP && Arrays.asList(PacketAnalysisConfig.getConfigAsString("tcp.protocol.filter").split(",")).contains("http"))){
			logger.debug("tcp filtered");
			return TcpProtocol.TCP;
		}
		return null;
*/

	}
	
	
	private static TcpProtocol parseProtocol(byte[] data){

		if(data.length < 11){
			byte[] dataByteSub = new byte[data.length];
			System.arraycopy(data,0,dataByteSub,0,data.length);//根据HTTP请求关键字的长度，取前11个字节,不足11的有几个就取几个
			String dataStringSub = new String(dataByteSub);

			for(String http_type : HTTP_type){//判断前11个字节中是否包含HTTP的30个关键字中的某一个
				if(dataStringSub.contains(http_type)){
					return TcpProtocol.HTTP;
				}
			}
		}else{
			byte[] dataByteSub = new byte[11];
			System.arraycopy(data,0,dataByteSub,0,11);//根据HTTP请求关键字的长度，取前11个字节
			String dataStringSub = new String(dataByteSub);

			for(String http_type : HTTP_type){//判断前11个字节中是否包含HTTP的30个关键字中的某一个
				if(dataStringSub.contains(http_type)){
					return TcpProtocol.HTTP;
				}
			}
		}
		return null;
	}

}
